package com.qqt.csr.common.acl.aics;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.qqt.csr.common.acl.aics.req.QueryingCsMemberDTO;
import com.qqt.csr.common.acl.aics.resp.ChannelInfoDTO;
import com.qqt.csr.common.acl.aics.resp.CsMemberInfoDTO;
import com.qqt.csr.common.acl.auth.AuthServiceClient;
import com.qqt.csr.common.exception.BaseException;
import com.qqt.csr.common.exception.BizException;
import com.qqt.csr.common.exception.StatusCode;
import com.qqt.csr.common.utils.CacheKeyUtil;
import com.qqt.csr.common.utils.HttpClientUtil;
import com.qqt.csr.common.utils.JsonUtil;
import com.qqt.csr.common.utils.ServiceAssert;
import com.qqt.csr.common.vo.resp.PageResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 智能客服适配器
 */
@Slf4j
@Component
public class AICustomerServiceClient {
    @Value("${aiCustomer.queryCsMemberListUrl}")
    private String queryCsMemberListUrl;
    @Value("${aiCustomer.queryCsMemberInfoUrl}")
    private String queryCsMemberInfoUrl;
    @Value("${aiCustomer.queryChannelInfoUrl}")
    private String queryChannelInfoUrl;
    @Value("${aiCustomer.queryChannelListUrl}")
    private String queryChannelListUrl;
    @Value("${aiCustomer.checkVisitorTokenUrl}")
    private String checkVisitorTokenUrl;
    @Value("${aiCustomer.tenantId}")
    private String tenantId;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private AuthServiceClient authServiceClient;

    /**
     * 根据条件查询客服列表
     *
     * @param req
     * @return
     */
    public PageResponse<CsMemberInfoDTO> queryCsMemberList(QueryingCsMemberDTO req) {
        try {
            String reqStr = JsonUtil.toJson(req);
            log.info("开始调用智能客服获取客服信息接口，req:{}", reqStr);
            JSONObject respJson = Optional.ofNullable(HttpClientUtil.postJson(queryCsMemberListUrl, reqStr, reqHeader(), JSONObject.class)).orElseGet(JSONObject::new);
            log.info("结束调用智能客服获取客服信息接口，resp:{}", respJson);
            if (!"200".equalsIgnoreCase(respJson.getString("code"))) {
                String errorMsg = Optional.ofNullable(respJson.getString("msg")).orElse(StatusCode.Common.THIRD_API_ERROR.getMessage());
                throw new BizException(StatusCode.Common.THIRD_API_ERROR.getCode(), errorMsg);
            }
            List<JSONObject> respDataList = JsonUtil.toList(respJson.getString("rows"), JSONObject.class);
            List<CsMemberInfoDTO> resultList = respDataList.stream()
                    .map(data -> CsMemberInfoDTO.builder()
                            .userId(data.getLong("userId"))
                            .userName(data.getString("userName"))
                            .nickName(data.getString("nickName"))
                            .employeeNo(data.getString("jobId"))
                            .status(data.getInteger("status"))
                            .headImg(data.getString("avatar"))
                            .receptionLimit(data.getInteger("receptionLimit"))
                            .deptName(Lists.newArrayList(
                                    Optional.ofNullable(data.getJSONObject("dept"))
                                            .map(deptObj -> deptObj.getString("deptName"))
                                            .orElse(StringUtils.EMPTY)
                            ))
                            .roleName(
                                    Optional.ofNullable(data.getJSONArray("roles"))
                                            .orElseGet(JSONArray::new)
                                            .stream()
                                            .map(role -> (JSONObject) role)
                                            .map(roleObj -> roleObj.getString("roleName"))
                                            .collect(Collectors.toList())
                            )
                            .build())
                    .collect(Collectors.toList());
            Long total = Optional.ofNullable(respJson.getLong("total")).orElse(0L);
            return new PageResponse<>(total, req.getPageSize(), req.getPageNum(), resultList);
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("调用智能客服获取客服信息接口异常", e);
            throw new BizException(StatusCode.Common.THIRD_API_ERROR);
        }
    }

    /**
     * 根据渠道id查询渠道信息
     *
     * @param channelId
     * @return
     */
    public ChannelInfoDTO queryChannelInfo(String channelId) {
        if(StringUtils.isBlank(channelId)){
            return null;
        }
        String redisKey = String.format(CacheKeyUtil.ChannelInfo.CHANNEL_INFO, channelId);
        ChannelInfoDTO channelInfoDTO = Optional.ofNullable(redissonClient.getBucket(redisKey).get())
                .map(o -> JsonUtil.toObject(o.toString(), ChannelInfoDTO.class))
                .orElse(null);
        if (channelInfoDTO != null) {
            return channelInfoDTO;
        }
        try {
            log.info("开始调用智能客服查询渠道信息接口，channelId:{}", channelId);
            String url = queryChannelInfoUrl + channelId;
            String respStr = HttpClientUtil.get(url, Maps.newHashMap(), reqHeader());
            log.info("结束调用智能客服查询渠道信息接口，resp:{}", respStr);
            JSONObject respJson = Optional.ofNullable(JsonUtil.toObject(respStr, JSONObject.class)).orElseGet(JSONObject::new);
            if (!"200".equalsIgnoreCase(respJson.getString("code"))) {
                String errorMsg = Optional.ofNullable(respJson.getString("msg")).orElse(StatusCode.Common.THIRD_API_ERROR.getMessage());
                throw new BizException(StatusCode.Common.THIRD_API_ERROR.getCode(), errorMsg);
            }

            JSONObject data = respJson.getJSONObject("data");
            if (data == null) {
                return null;
            }

            channelInfoDTO = ChannelInfoDTO.builder()
                    .id(data.getString("channelId"))
                    .name(data.getString("channelName"))
                    // .skillSetId(data.getLong("customerGroupId"))
                    .routeId(data.getInteger("routeId"))
                    .appearanceType(data.getInteger("appearanceType"))
                    .build();
            redissonClient.getBucket(redisKey).setAsync(JsonUtil.toJson(channelInfoDTO), Duration.of(CacheKeyUtil.EXPIRE_TIME_30S, ChronoUnit.MILLIS));
            return channelInfoDTO;
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("调用智能客服查询渠道信息接口异常", e);
            throw new BizException(StatusCode.Common.THIRD_API_ERROR);
        }
    }

    /**
     * 根据路由id查询渠道信息
     * @param routeIdList
     * @return
     */
    public Map<Integer,List<ChannelInfoDTO>> queryChannelListBy(List<Integer> routeIdList) {
        if(CollectionUtils.isEmpty(routeIdList)){
            return Maps.newHashMap();
        }
        try {
            JSONObject req = new JSONObject();
            req.put("routeIdList", routeIdList);
            String reqStr = req.toJSONString();
            log.info("开始调用根据路由id查询渠道信息接口，req:{}", reqStr);
            JSONObject respJson = Optional.ofNullable(HttpClientUtil.postJson(queryChannelListUrl, reqStr, reqHeader(), JSONObject.class)).orElseGet(JSONObject::new);
            log.info("结束调用根据路由id查询渠道信息接口，resp:{}", respJson);
            if (!"200".equalsIgnoreCase(respJson.getString("code"))) {
                String errorMsg = Optional.ofNullable(respJson.getString("msg")).orElse(StatusCode.Common.THIRD_API_ERROR.getMessage());
                throw new BizException(StatusCode.Common.THIRD_API_ERROR.getCode(), errorMsg);
            }
            List<JSONObject> respDataList = JsonUtil.toList(respJson.getString("data"), JSONObject.class);
            return respDataList.stream()
                    .map(data -> ChannelInfoDTO.builder()
                            .id(data.getString("channelId"))
                            .name(data.getString("channelName"))
                            .routeId(data.getInteger("routeId"))
                            .appearanceType(data.getInteger("appearanceType"))
                            .build())
                    .collect(Collectors.groupingBy(ChannelInfoDTO::getRouteId));
        }catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("调用根据路由id查询渠道信息接口异常", e);
            throw new BizException(StatusCode.Common.THIRD_API_ERROR);
        }
    }

    /**
     * 根据用户id查询用户信息
     * @param csIdList
     * @return
     */
    public List<CsMemberInfoDTO> queryByIdList(List<Long> csIdList) {
        if (CollectionUtils.isEmpty(csIdList)) {
            return Lists.newArrayList();
        }
        List<CsMemberInfoDTO> result = new ArrayList<>();
        // List<Long> needQueryCsIdList = new ArrayList<>();
        //
        // if (csIdList.size() == 1) {
        //     String redisKey = String.format(CacheKeyUtil.CsMemberInfo.CS_NORMAL_INFO, csIdList.get(0));
        //     CsMemberInfoDTO csMemberInfoDTO = Optional.ofNullable(redissonClient.getBucket(redisKey).get())
        //             .map(o -> JsonUtil.toObject(o.toString(), CsMemberInfoDTO.class)).orElse(null);
        //     if (csMemberInfoDTO != null) {
        //         result.add(csMemberInfoDTO);
        //     } else {
        //         needQueryCsIdList.add(csIdList.get(0));
        //     }
        // } else {
        //     RBatch redisBatch = redissonClient.createBatch();
        //     csIdList.forEach(csId -> {
        //         String redisKey = String.format(CacheKeyUtil.CsMemberInfo.CS_NORMAL_INFO, csId);
        //         redisBatch.getBucket(redisKey).getAsync();
        //     });
        //     BatchResult batchResult = redisBatch.execute();
        //     List<Object> objectList = batchResult.getResponses();
        //     for (int i = 0; i < csIdList.size(); i++) {
        //         Long csId = csIdList.get(i);
        //         Object csInfoJson = objectList.get(i);
        //         if (csInfoJson != null) {
        //             CsMemberInfoDTO csMemberInfoDTO = JsonUtil.toObject(csInfoJson.toString(), CsMemberInfoDTO.class);
        //             result.add(csMemberInfoDTO);
        //         } else {
        //             needQueryCsIdList.add(csId);
        //         }
        //     }
        // }
        //
        // if (CollectionUtils.isEmpty(needQueryCsIdList)) {
        //     return result;
        // }

        List<CsMemberInfoDTO> csMemberInfoDTOList = new ArrayList<>();
        try {
            JSONObject req = new JSONObject();
            // req.put("userIdList", needQueryCsIdList);
            req.put("userIdList", csIdList);
            String reqStr = req.toJSONString();
            log.info("开始调用智能客服获取客服基本信息接口，req:{}", reqStr);
            JSONObject respJson = Optional.ofNullable(HttpClientUtil.postJson(queryCsMemberInfoUrl, reqStr, reqHeader(), JSONObject.class)).orElseGet(JSONObject::new);
            log.info("结束调用智能客服获取客服基本信息接口，resp:{}", respJson);
            if (!"200".equalsIgnoreCase(respJson.getString("code"))) {
                String errorMsg = Optional.ofNullable(respJson.getString("msg")).orElse(StatusCode.Common.THIRD_API_ERROR.getMessage());
                throw new BizException(StatusCode.Common.THIRD_API_ERROR.getCode(), errorMsg);
            }
            List<JSONObject> respDataList = JsonUtil.toList(respJson.getString("data"), JSONObject.class);
            csMemberInfoDTOList = respDataList.stream()
                    .map(data -> CsMemberInfoDTO.builder()
                            .userId(data.getLong("userId"))
                            .userName(data.getString("account"))
                            .nickName(data.getString("nickName"))
                            .headImg(data.getString("headImg"))
                            .status(data.getInteger("status"))
                            .receptionLimit(data.getInteger("receptionLimit"))
                            .build())
                    .collect(Collectors.toList());
            result.addAll(csMemberInfoDTOList);
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("调用智能客服获取客服信息接口异常", e);
            throw new BizException(StatusCode.Common.THIRD_API_ERROR);
        }

        // if (csMemberInfoDTOList.size() == 1) {
        //     String redisKey = String.format(CacheKeyUtil.CsMemberInfo.CS_NORMAL_INFO, csMemberInfoDTOList.get(0).getUserId());
        //     redissonClient.getBucket(redisKey).setAsync(JsonUtil.toJson(csMemberInfoDTOList.get(0)), Duration.of(CacheKeyUtil.EXPIRE_TIME_30S, ChronoUnit.MILLIS));
        // } else {
        //     RBatch redisBatch = redissonClient.createBatch();
        //     csMemberInfoDTOList.forEach(csInfo -> {
        //         String redisKey = String.format(CacheKeyUtil.CsMemberInfo.CS_NORMAL_INFO, csInfo.getUserId());
        //         redisBatch.getBucket(redisKey).setAsync(JsonUtil.toJson(csInfo), Duration.of(CacheKeyUtil.EXPIRE_TIME_30S, ChronoUnit.MILLIS));
        //     });
        //     redisBatch.execute();
        // }
        return result;
    }

    /**
     * 获取正常状态的客服列表
     *
     * @param csIdList
     * @return
     */
    public List<CsMemberInfoDTO> getNormalListBy(List<Long> csIdList) {
        return queryByIdList(csIdList).stream().filter(csInfo -> csInfo.getStatus() == 0).collect(Collectors.toList());
    }

    /**
     * 校验访客端Token身份
     *
     * @param tenantId
     * @param visitorToken
     * @return
     */
    public void checkVisitorToken(String tenantId, String visitorToken) {
        try {
            JSONObject req = new JSONObject();
            req.put("accessToken", visitorToken);
            req.put("tenantId", tenantId);
            String reqStr = req.toJSONString();
            log.info("开始调用智能客服校验访客端Token身份接口，req:{}", reqStr);
            JSONObject respJson = Optional.ofNullable(HttpClientUtil.postJson(checkVisitorTokenUrl, reqStr, reqHeader(), JSONObject.class)).orElseGet(JSONObject::new);
            log.info("结束调用智能客服校验访客端Token身份接口，resp:{}", respJson);
            boolean result = "200".equalsIgnoreCase(respJson.getString("code"));
            ServiceAssert.isTrue(result, StatusCode.Common.NO_TOKEN.getCode(), respJson.getString("msg"));
        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("调用智能客服校验访客端Token身份异常", e);
            throw new BizException(StatusCode.Common.THIRD_API_ERROR);
        }
    }

    private Map<String, String> reqHeader() {
        Map<String, String> header = new HashMap<>();
        header.put("accessToken", authServiceClient.getAppAccessToken());
        header.put("Tenant-Id", tenantId);
        return header;
    }
}
